﻿using Bigway.Common.Extensions;
using Bigway.Common.Utils;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SqlSugar;

namespace Bigway.Common.Jobs;

public class DailyDatabaseBackupJob(IServiceScopeFactory serviceScopeFactory,
    string systemId) : BaseBackgroundJob<DailyDatabaseBackupJob>(serviceScopeFactory, systemId)
{
    protected override Task DoJob(IServiceProvider serviceProvider, ILogger<DailyDatabaseBackupJob> logger)
    {
        var dbInfo = serviceProvider.GetRequiredService<SqliteDbInfo>();
        var homeDir = Environment.CurrentDirectory;
        var backupDir = Path.Combine(homeDir, "DatabaseBackups");
        if (!Directory.Exists(backupDir))
        {
            Directory.CreateDirectory(backupDir);
        }

        var backupFileInfos = FileUtils.GetFileInfosOrderByCreationTime(backupDir);

        if (IsBackupNeeded(backupFileInfos, new FileInfo(dbInfo.FilePath)))
        {
            var backupFileName = dbInfo.Name + " " +
                                 DateOnlyExtensions.TodayAsString() + ".db";
            var backupFilePath = Path.Combine(backupDir, backupFileName);
            var db = serviceProvider.GetRequiredKeyedService<ISqlSugarClient>(IocKeys.SqliteDbKey);
            db.DbMaintenance.BackupDataBase(dbInfo.Name, backupFilePath);
            logger.LogInformation("Successfully backed up database to file {BackupFilePath}", backupFilePath);
        }
        else
        {
            logger.LogInformation("No changes since last backup, skipping current one");
        }

        var outdatedBackupCount = CleanupOutdatedBackups(backupFileInfos);

        logger.LogInformation("Successfully cleaned up {OutdatedBackupCount} outdated backup files", outdatedBackupCount);

        return Task.CompletedTask;
    }


    private static bool IsBackupNeeded(List<FileInfo> backupFileInfos, FileInfo dbFileInfo)
    {
        if (backupFileInfos.Count == 0)
            return true;

        var latestBackupFileInfo = backupFileInfos[^1];
        return latestBackupFileInfo.CreationTimeUtc < dbFileInfo.LastWriteTimeUtc;
    }
    

    private static int CleanupOutdatedBackups(List<FileInfo> fileInfos)
    {
        var twoDaysAgo = DateTime.UtcNow.AddDays(-2);
        var outdatedFiles = fileInfos
            .Where(fileInfo => fileInfo.CreationTimeUtc <= twoDaysAgo)
            .ToList();

        if (outdatedFiles.Count == fileInfos.Count)
        {
            // All backup files are outdated, at least keep latest backup
            foreach (var fileInfo in outdatedFiles.SkipLast(1)) 
                File.Delete(fileInfo.FullName);

            return outdatedFiles.Count - 1;
        }

        foreach (var outdatedFile in outdatedFiles)
        {
            File.Delete(outdatedFile.FullName);
        }

        return outdatedFiles.Count;
    }
}